package com.emeraldparser.symbol;

import java.io.IOException;
import java.io.Reader;
import java.util.Iterator;
import java.util.Map;

import com.google.common.collect.AbstractIterator;
import com.google.common.collect.Iterators;
import com.google.common.collect.Maps;

public class Symbols {

	private static final Symbol<?> startOfInput = new Symbol<Object>(SymbolClasses.startOfInput(), null);
	private static final Symbol<?> endOfInput = new Symbol<Object>(SymbolClasses.endOfInput(), null);
	private static final Map<Character, Symbol<Character>> symbolsByCharacter = Maps.newHashMap();

	@SuppressWarnings("unchecked")
	public static Iterator<? extends Symbol<?>> iterator(final Reader reader) {
		return Iterators.concat(
				Iterators.forArray(startOfInput),
				
				new AbstractIterator<Symbol<?>>() {
					@Override
					protected Symbol<?> computeNext() {
						int value;
						try {
							value = reader.read();
						} catch (IOException e) {
							throw new RuntimeException("Error reading characters", e);
						}
						
						if (value == -1) {
							return endOfData();
						}
						
						char character = (char) value;
						
						Symbol<Character> symbol = symbolsByCharacter.get(character);
						
						if (symbol == null) {
							symbol = new Symbol<Character>(SymbolClasses.literal(character), character);
							symbolsByCharacter.put(character, symbol);
						}
						
						return symbol;
					}
				},
				
				Iterators.forArray(endOfInput)
			);
	}

}
